/**
 * mod_googlemaps.js
 * This module adds google base maps to the map
 * and creates street view and earth tabs in the map map accordion,
 * linking map move to the street view and earth objects.
 * 
 * @author 		Tobin Bradley
 * @license 	MIT 
 */

var ge, streetview;

// Load Google Earth
google.load('earth', '1', {other_params:'sensor=false'});

$(window).load(function() {
    // Add google map layers to map
    var gmap = new OpenLayers.Layer.Google(
		"Google Streets",
		{'sphericalMercator': true, numZoomLevels: 18, MIN_ZOOM_LEVEL: 9, MAX_ZOOM_LEVEL: 19 }
	);
	var gsat = new OpenLayers.Layer.Google(
		"Google Satellite",
		{type: google.maps.MapTypeId.SATELLITE, 'sphericalMercator': true, numZoomLevels: 18, MIN_ZOOM_LEVEL: 9, MAX_ZOOM_LEVEL: 19 }
	);
	var ghyb = new OpenLayers.Layer.Google(
		"Google Hybrid",
		{type: google.maps.MapTypeId.HYBRID, 'sphericalMercator': true, numZoomLevels: 18, MIN_ZOOM_LEVEL: 9, MAX_ZOOM_LEVEL: 19 }
	);
	var gphy = new OpenLayers.Layer.Google(
		"Google Physical",
		{type: google.maps.MapTypeId.TERRAIN, 'sphericalMercator': true, numZoomLevels: 20, MIN_ZOOM_LEVEL: 9, MAX_ZOOM_LEVEL: 15 }
	);
	map.addLayers([gmap, gsat, ghyb, gphy ]);
    
    
    // Add Streetview and Earth to map tab
    $("#accordion-map")
		.append("<h3 id='STREETVIEW'><a href='#'>Google Street View</a></h3><div><div id='widget-streetview' class='widgetmap'></div></div>")
		.append("<h3 id='EARTH'><a href='#'>Google Earth</a></h3><div><div id='widget-earth' class='widgetmap'></div></div>")
		.accordion("destroy").accordion({header: "h3", collapsible: true, autoHeight: false }).bind("accordionchange", function(event, ui) {
        if (ui.newHeader[0]) processAccordionMapChange(ui.newHeader[0].id);
    });

	
    // Hook streetview to map move event
	map.events.register("moveend", map, function(e) {
		mapactive = $("#accordion-map h3").eq($('#accordion-map').accordion('option', 'active')).attr("id");
		if (mapactive == "STREETVIEW") {
			widgetMaps("Google Street View", map.getCenter(), false);
		}
		if (mapactive == "EARTH") {
			widgetMaps("Google Earth", map.getCenter(), false);
		}
	});
    
});
    

/*  Run Code When Active Map Accordion Changes  */
function processAccordionMapChange(accordionValue) {
    switch (accordionValue) {
		case "STREETVIEW":
				widgetMaps("Google Street View", map.getCenter(), true);
		break;
		case "EARTH":
				widgetMaps("Google Earth", map.getCenter(), true);
		break;
	}
}


    
/**
 * Handle widget map creation and panning
 * @param {string} maptype
 * @param {Object} longlat
 * @param {boolean} reset
 */
function widgetMaps(maptype, longlat, reset) {
	var lonlatGCS = OpenLayers.Layer.SphericalMercator.inverseMercator(longlat.lon, longlat.lat);
    if (maptype == "Google Street View") {
        if (streetview == null || reset ) {
			streetview = new  google.maps.StreetViewPanorama(document.getElementById("widget-streetview"));
		}
				
		var theloc = new google.maps.LatLng(lonlatGCS.lat,lonlatGCS.lon);
		streetview.setPosition(theloc);
		 
		 google.maps.event.addListener(streetview, 'position_changed', function() {
			var angle = computeAngle(theloc, streetview.getPosition());
			streetview.setPov({heading:angle, pitch:0, zoom:1}); 
		});
	}
	else if (maptype == "Google Earth") {
		if (ge == null || reset) {
			$("#widget-earth").empty();
			google.earth.createInstance('widget-earth', function(instance){
				ge = instance;
				instance.getWindow().setVisibility(true);

				ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS, true);
				ge.getLayerRoot().enableLayerById(ge.LAYER_TERRAIN, true);
				geZoom(longlat);
				
			});
		}
		else {
			geZoom(longlat);
		}
	}
	else {
		return;
	}
}

/**
 * Function to zoom for Google Earth. External because GE loads asynchronously.
 * Note map.getScale()/40 for range and the tilt angle. Tweak those to taste.
 */
function geZoom(longlat) {
	// Update the view in Google Earth
		var lonlatGCS = OpenLayers.Layer.SphericalMercator.inverseMercator(longlat.lon, longlat.lat);
		var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
		lookAt.setLatitude(lonlatGCS.lat);
		lookAt.setLongitude(lonlatGCS.lon);
		lookAt.setRange(map.getScale()/40);
		lookAt.setTilt(45);
		ge.getView().setAbstractView(lookAt);
}


/**
 * These functions support google street view.
 * Principally for setting the street view angle relative to map center.
 */
function showPanoData(panoData) {
    if (panoData.code == 600) {
		$("#widget-streetview").html("No street view data available for this location.");	
    }
    else {
		$("#widget-streetview").empty();
	   var longlat = map.getCenter();
	   var lonlatGCS = OpenLayers.Layer.SphericalMercator.inverseMercator(longlat.lon, longlat.lat);
	   var theloc = new GLatLng(lonlatGCS.lat,lonlatGCS.lon);
        var angle = computeAngle(theloc, panoData.location.latlng);
        streetview.setLocationAndPOV(panoData.location.latlng, {yaw: angle});
    }
}
function computeAngle(endLatLng, startLatLng) {
      var DEGREE_PER_RADIAN = 57.2957795;
      var RADIAN_PER_DEGREE = 0.017453;

      var dlat = endLatLng.lat() - startLatLng.lat();
      var dlng = endLatLng.lng() - startLatLng.lng();
      // We multiply dlng with cos(endLat), since the two points are very closeby,
      // so we assume their cos values are approximately equal.
      var yaw = Math.atan2(dlng * Math.cos(endLatLng.lat() * RADIAN_PER_DEGREE), dlat) * DEGREE_PER_RADIAN;
      return wrapAngle(yaw);
}
function wrapAngle(angle) {
    if (angle >= 360) {
      angle -= 360;
    } else if (angle < 0) {
     angle += 360;
    }
    return angle;
}